/*-----------------------------------------------------------------------*/
/* Low level disk I/O module SKELETON for FatFs     (C)ChaN, 2019        */
/*-----------------------------------------------------------------------*/
/* If a working storage control module is available, it should be        */
/* attached to the FatFs via a glue function rather than modifying it.   */
/* This is an example of glue functions to attach various exsisting      */
/* storage control modules to the FatFs module with a defined API.       */
/*-----------------------------------------------------------------------*/

#include "Middlewares/FATFS/ff.h"	  /* Obtains integer types */
#include "Middlewares/FATFS/diskio.h" /* Declarations of disk functions */

#include "BSP/SD/sdcard.h" //自己的SD卡驱动
#include "BSP/W25Qxx/w25qxx.h"
#include "main.h"

/* Definitions of physical drive number for each drive */
#define DEV_SD 0				   /* SD卡 */
#define DEV_FLASH 1				   /* Flash disk */
#define SPI_FLASH_SECTOR_SIZE 4096 /* Flash块大小 */
/*-----------------------------------------------------------------------*/
/* Get Drive Status                                                      */
/*-----------------------------------------------------------------------*/

DSTATUS disk_status(
	BYTE pdrv /* Physical drive nmuber to identify the drive */
)
{
	int result;

	switch (pdrv)
	{
	case DEV_SD:
		result = 0; // 0:OK;其他:错误代码
		break;
	case DEV_FLASH:
		result = 0; // 0:OK;其他:错误代码
		break;
	default:
		result = 1;
		break;
	}

	if (result == 0)
		return (DRESULT)0;
	else
		return STA_NOINIT;
}

/*-----------------------------------------------------------------------*/
/* Inidialize a Drive                                                    */
/*-----------------------------------------------------------------------*/

DSTATUS disk_initialize(
	BYTE pdrv /* Physical drive nmuber to identify the drive */
)
{
	int result;

	switch (pdrv)
	{
	case DEV_SD:
		result = sd_init(); // 0:OK;其他:错误代码
		break;
	case DEV_FLASH:
		if (w25qxx_read_id() == 0xFFFF || w25qxx_read_id() == 0x0000)
			result = 1;
		else
			result = 0;
		break;
	default:
		result = 1;
		break;
	}

	if (result == 0)
		return (DRESULT)0;
	else
		return STA_NOINIT;
}

/*-----------------------------------------------------------------------*/
/* Read Sector(s)                                                        */
/*-----------------------------------------------------------------------*/

DRESULT disk_read(
	BYTE pdrv,	  /* Physical drive nmuber to identify the drive */
	BYTE *buff,	  /* Data buffer to store read data */
	LBA_t sector, /* Start sector in LBA */
	UINT count	  /* Number of sectors to read */
)
{
	int result;

	switch (pdrv)
	{
	case DEV_SD:
		result = sd_read_disk((BYTE *)buff, sector, count);
		break;

	case DEV_FLASH:
		for (; count > 0; count--)
		{
			w25qxx_read((BYTE *)buff, sector * SPI_FLASH_SECTOR_SIZE, SPI_FLASH_SECTOR_SIZE);
			sector++;
			buff += SPI_FLASH_SECTOR_SIZE;
		}
		result = 0;
		break;
	default:
		result = 1;
		break;
	}

	if (result == 0)
		return (DRESULT)0;
	else
		return (DRESULT)STA_NOINIT;
}

/*-----------------------------------------------------------------------*/
/* Write Sector(s)                                                       */
/*-----------------------------------------------------------------------*/

#if FF_FS_READONLY == 0

DRESULT disk_write(
	BYTE pdrv,		  /* Physical drive nmuber to identify the drive */
	const BYTE *buff, /* Data to be written */
	LBA_t sector,	  /* Start sector in LBA */
	UINT count		  /* Number of sectors to write */
)
{
	int result;

	switch (pdrv)
	{
	case DEV_SD:
		result = sd_write_disk((BYTE *)buff, sector, count);
		break;

	case DEV_FLASH:
		for (; count > 0; count--)
		{
			w25qxx_write((BYTE *)buff, sector * SPI_FLASH_SECTOR_SIZE, SPI_FLASH_SECTOR_SIZE);
			sector++;
			buff += SPI_FLASH_SECTOR_SIZE;
		}
		result = 0;
		break;
	default:
		result = 1;
		break;
	}

	if (result == 0)
		return (DRESULT)0;
	else
		return (DRESULT)STA_NOINIT;
}

#endif

/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions                                               */
/*-----------------------------------------------------------------------*/

/**
 * @brief       获取其他控制参数
 * @param       pdrv   : 磁盘编号0~9
 * @param       ctrl   : 控制代码
 * @param       buff   : 发送/接收缓冲区指针
 * @retval      执行结果(参见FATFS, DRESULT的定义)
 */
DRESULT disk_ioctl(
	BYTE pdrv, /* Physical drive number (0..) */
	BYTE cmd,  /* Control code */
	void *buff /* Buffer to send/receive control data */
)
{
	DRESULT res;

	if (pdrv == DEV_FLASH) /* 外部FLASH */
	{
		switch (cmd)
		{
		case GET_SECTOR_SIZE:
			*(WORD *)buff = SPI_FLASH_SECTOR_SIZE;
			res = RES_OK;
			break;

		case GET_SECTOR_COUNT:
			*(DWORD *)buff = 2 * 1024;
			res = RES_OK;
			break;

		default:
			res = RES_PARERR;
			break;
		}
	}

	else if (pdrv == DEV_SD) /* 外部FLASH */
	{
		switch (cmd)
		{
		case GET_SECTOR_SIZE:
			*(WORD *)buff = 512;
			res = RES_OK;
			break;

		case GET_SECTOR_COUNT:
			*(DWORD *)buff = 32 * 1024;
			res = RES_OK;
			break;

		default:
			res = RES_PARERR;
			break;
		}
	}

	return res;
	// return (DRESULT)0;
}
